/**
 * 
 */
package com.dalonedrow.module.hq.systems;

import com.dalonedrow.engine.systems.JOGLErrorHandler;
import com.dalonedrow.engine.systems.base.Diceroller;
import com.dalonedrow.engine.systems.base.Interactive;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;
import com.dalonedrow.module.hq.rpg.HQInteractiveObject;
import com.dalonedrow.module.hq.ui.views.DungeonScreenView;
import com.dalonedrow.module.hq.ui.widgets.HQActionMenu;
import com.dalonedrow.pooled.PooledStringBuilder;
import com.dalonedrow.pooled.StringBuilderPool;

/**
 * @author Donald
 */
public final class HQTurn {
	/** the one and only instance of the <code>HQTurn</code> class. */
	private static HQTurn	instance;
	/**
	 * Gives access to the singleton instance of {@link HQTurn}.
	 * @return {@link HQTurn}
	 */
	public static HQTurn getInstance() {
		if (HQTurn.instance == null) {
			HQTurn.instance = new HQTurn();
		}
		return HQTurn.instance;
	}
	/** all interactive objects in play. */
	private int[]	ios;
	/** the number of interactive objects in play. */
	private int		numIosInPlay;
	/**
	 * Adds an IO to the game turn.
	 * @param ioid the IO's reference id
	 */
	public void addIO(final int ioid) {
		if (!Interactive.getInstance().hasIO(ioid)) {
			JOGLErrorHandler.getInstance().fatalError(
					new Exception("Invalid IO - " + ioid));
		}
		if (ios == null) {
			ios = new int[0];
		}
		// check to see if io is already tracked
		boolean inList = false;
		int index;
		for (index = 0; index < ios.length; index++) {
			if (ios[index] == ioid
					&& Interactive.getInstance().hasIO(ios[index])) {
				inList = true;
				break;
			}
		}
		if (!inList) {
			// add io to map
			index = numIosInPlay++;
			if (index >= ios.length) {
				// copy ios array
				int[] dest = new int[ios.length + 1];
				System.arraycopy(ios, 0, dest, 0, ios.length);
				ios = dest;
				dest = null;
			}
			ios[index] = ioid;
		}
	}
	/**
	 * Begins the turn for all IOs, assigning movement points, and checking
	 * spell statuses, etc...
	 * @throws Exception if an error occurs
	 */
	public void beginTurnForIOs() throws Exception {
		final int six = 6;
		for (int i = 0; i < numIosInPlay; i++) {
			if (!Interactive.getInstance().hasIO(ios[i])) {
				removeIO(ios[i]);
				continue;
			}
			HQInteractiveObject io =
					(HQInteractiveObject) Interactive.getInstance().getIO(
							ios[i]);
			if (io.hasIOFlag(GlobalConstants.IO_01_PC)) {
				int moves = Diceroller.getInstance().rollXdY(
						(int) io.getPCData().getFullMovement(),
						six
						);
				System.out.println("**setting moves for IO " + ios[i] + ":" + moves);
				io.getScript().setLocalVariable(
						"movesLeft", new Integer(moves));
				io.getScript().setLocalVariable(
						"movesMaxInTurn", new Integer(moves));
			} else if (io.hasIOFlag(GlobalConstants.IO_03_NPC)) {
				// to do
			}
		}
	}
	/** Moves to the next IO's turn cycle. */
	public void nextIOTurnCycle() {
		System.out.println("**HQTurn.nextIOTurnCycle()");
		try {
			int ioid =
					HQScript.getInstance().getGlobalIntVariableValue("ioTurn");
			System.out.println("current io turn " + ioid);
			// found an IO that still needs a turn
			boolean nextIOFound = false;
			for (int i = 0; i < ios.length; i++) {
				if (ios[i] == ioid
						&& i + 1 < ios.length) {
					HQScript.getInstance().setGlobalVariable(
							"ioTurn", new Integer(ios[++i]));
					nextIOFound = true;
					break;
				}
			}
			if (!nextIOFound) {
				HQScript.getInstance().setGlobalVariable(
						"ioTurn",
						new Integer(HQController.getInstance().getPcId()));
			}
			ioid = HQScript.getInstance().getGlobalIntVariableValue("ioTurn");
			System.out.println("current io turn " + ioid);
			// reset the map's pathfinder for all travel locations
			HQMap.getInstance().resetTravelLocations();
			HQMap.getInstance().centerMapOnIO(ioid);
			if (!nextIOFound) {
				// all IOs had a move. go to next turn
				nextTurn();
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/** Starts the next turn. */
	public void nextTurn() {
		System.out.println("**HQTurn.nextTurn()");
		try {
			// update the turn number
			int turn = HQScript.getInstance().getGlobalIntVariableValue(
					"currentTurn");
			HQScript.getInstance().setGlobalVariable(
					"currentTurn", ++turn);

			PooledStringBuilder sb = 
				StringBuilderPool.getInstance().getStringBuilder();
			sb.append("---------- TURN ");
			sb.append(turn);
			sb.append(" ----------\n");
			DungeonScreenView.getInstance().sendPlayerMessage(sb.toString());
			sb.returnToPool();
			// TO DO - check for time running out or events that happen at next
			// turn
			// TO DO - check to see if player lost turn, and remove spells that
			// expire
			HQTurn.getInstance().beginTurnForIOs();
			// reset map
			HQMap.getInstance().setMode(GlobalConstants.MAP_MODE_00_FREE);
			// reset all IOs movement
			// reset movement paths
			HQMap.getInstance().resetTravelLocations();
			// reset actions for the next turn
			HQActionMenu.getInstance().resetActionTaken();
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	public void removeIO(final int ioid) {
		if (!Interactive.getInstance().hasIO(ioid)) {
			JOGLErrorHandler.getInstance().fatalError(
					new Exception("Invalid IO - " + ioid));
		}
		// check to see if io is already tracked
		boolean inList = false;
		int index = 0;
		for (; index < ios.length; index++) {
			if (Interactive.getInstance().hasIO(ios[index])) {
				inList = true;
				break;
			}
		}
		if (inList) {
			if (index == 0) {
				// move everything back one position in ios array
				int[] dest = new int[ios.length];
				System.arraycopy(ios, 1, dest, 0, ios.length - 1);
				dest[ios.length - 1] = -1;
				ios = dest;
				dest = null;
			} else if (index == ios.length - 1) {
				// index is last index in array.
				// set last index value to invalid
				ios[index] = -1;
			} else {
				// index is somewhere in the middle
				int[] dest = new int[ios.length];
				// copy everything leading up to index
				System.arraycopy(ios, 0, dest, 0, index);
				// copy everything after index
				System.arraycopy(ios, index + 1, dest, index,
							ios.length - 1 - index);
				// last item in array is set to -1
				dest[ios.length - 1] = -1;
				ios = dest;
				dest = null;
			}
			numIosInPlay--;
		}
	}
	/*
	 * public void endIOTurn(final int ioid) throws Exception {
	 * System.out.println("**endIOTurn()"); int[] list =
	 * HQScript.getInstance().getGlobalIntArrayVariableValue( "turnOrder"); int
	 * nextId = -1; for (int i = 0; i < list.length; i++) { if (list[i] == ioid
	 * && i + 1 < list.length) { nextId = list[i + 1]; break; } } if (nextId ==
	 * -1) { nextId = list[0]; // GO TO NEXT TURN } // set next IO for turn if
	 * (nextId != -GlobalConstants.INT_999) { centerMapOnIO(nextId); } // go to
	 * next IO HQController.getInstance().nextIOTurnCycle(); }
	 */
	/**
	 * Updates the turn.
	 * @throws Exception if an error occurs
	 */
	public void update() throws Exception {
		// if the game is on the dungeon screen, the turn order is this:
		// 1 - player takes an action (this requires player input)
		// 2-4 - computer-controller players take an action and resolve
		// 5 - ZARGON takes an action
		// see if it is still player's turn
		int ioid = HQScript.getInstance().getGlobalIntVariableValue(
				"ioTurn");
		int pc = HQController.getInstance().getPcId();
		if (ioid != pc) {
			// computer controls all PCs that are not the player
			// get the IO
			HQInteractiveObject io =
					(HQInteractiveObject) Interactive.getInstance().getIO(
							ioid);
			if (io.hasIOFlag(GlobalConstants.IO_01_PC)) {
				// not the player's turn
				// take an action for the IO
				// TO DO
				// move to next IO for next update
				// MOVE THIS SOMEWHERE ELSE
				nextIOTurnCycle();
			} else if (io.hasIOFlag(GlobalConstants.IO_03_NPC)) {
				// ZARGON's MINION turn
				// take action for any enemy IOs on the map
				// TO DO
				// set it back to player's turn
				nextIOTurnCycle();
			}
		} else {
		}
	}
}
